import {
	encrypt,
	md5,
	ConvertHex,
	ConvertUtf8
} from './crypto.min.js'

export const base = process.env.BASE_URL||"https://127.0.0.1/";
export const loginPage = '/pages/start/start';//'/pages/login/login'

/**
 * GET 请求
 * @param uri
 * @param data
 * @param loadingText
 * @return {Promise<unknown>}
 */
export const get = (uri, data = {}, loadingText = '') => {
	const header = {}
	return request(uri, 'GET', data, header, loadingText)

}
/**
 * 表单格式的POST请求
 * @param uri
 * @param data
 * @param loadingText
 * @return {Promise<unknown>}
 */
export const formPost = (uri, data = {}, loadingText) => {
	const header = {
		'content-type': 'application/x-www-form-urlencoded'
	}
	return request(uri, 'POST', data, header, loadingText)
}
/**
 * JSON格式的POST请求
 * @param uri
 * @param data
 * @param loadingText
 * @return {Promise<unknown>}
 */
export const post = (uri, data = {}, loadingText) => {
	const header = {
		'content-type': 'application/json'
	}
	return request(uri, 'POST', data, header, loadingText)
}

/**
 * 封装AJAX请求，实现自动token管理
 * @param uri
 * @param method
 * @param data
 * @param header
 * @param loadingText
 * @return {Promise<unknown>}
 */
function request(uri, method, data, header = {}, loadingText) {
	setRequestHeader(header)
	return new Promise((resolve, reject) => {
		if (loadingText) {
			uni.showLoading({
				title: loadingText
			});
		}
		uni.request({
			url: base + uri,
			data: data,
			method: method,
			header: header,
			success: (res) => {
				if (res.statusCode == 401) {
					logout()
					uni.reLaunch({
						url: loginPage
					})
					reject(res.data)
					return
				}
				if (res.data.success) {
					resolve(res.data.data)
				} else {
					reject(res.data)
				}
			},
			fail(e) {
				reject(e)
			},
			complete() {
				if (loadingText) {
					uni.hideLoading()
				}
			}
		})
	})
}

/**
 * 获取后端系统配置信息，会在本地缓存
 * @return {Promise<unknown>}
 */
export const getSystemInfo = () => {
	return new Promise((resolve, reject) => {
		let _sysConfig = sysConfig()
		if (_sysConfig) {
			resolve(_sysConfig)
			return
		}
		get('system/fontConfig').then(r => {
			if (r.success) {
				sysConfig(r.data)
				resolve(r.data)
			} else {
				reject(r)
			}
		}).catch(reject)
	})

}
/**
 * 获取用户信息，会在本地缓存
 * @return {Promise<*>|Promise<Awaited<unknown>>}
 */
export const localUserInfo=()=>{
	const u=userInfo()
	if(u){
		return Promise.resolve(u)
	}else{
		return loadUserInfo()
	}
}
/**
 * 获取用户信息，不缓存
 * @return {Promise<*>}
 */
export const loadUserInfo = () => get('system/user_info').then(r=>{
	if(r){
		userInfo(r)
		return Promise.resolve(r)
	}else{
		return Promise.reject()
	}
})

/**
 * 通过用户名密码登录
 * @param username
 * @param password
 * @param uri 默认为 client/login
 * @return {Promise<void>}
 */
export function login(username,password,uri='client/login'){
	let t=Date.now()
	let ep=encrypt(password,t)
	return post(uri,{username:username,password:ep,t:t},'登录中').then(r=>{
		//存储数据
		token(r.token)
		Uk(r.uk)
		Un(r.un)
		userInfo(r.user)
	})
}
/**
 * 小程序用户自动登录
 * @param uri 登录地址，默认为 client/mp_auto_login
 */
export function mpLogin(uri = 'client/mp_auto_login') {
	return new Promise((resolve, reject) => {
		loadUserInfo().then(resolve).catch(e=>{
			wx.login({
				success(res) {
					if (res.code) {
						formPost(uri, {
							code: res.code
						}).then(data => {
							let user = data.user
							user.isNew=r.isNew
							//存储数据
							token(user.token)
							Uk(data.uk)
							Un(user.userType + user.username)
							userInfo(user)

							resolve(user)
						}).catch(e => {
							uni.showToast({
								icon: 'fail',
								title: e.message
							})
							reject(e)
						})
					} else {
						uni.showToast({
							icon: 'error',
							title: res.errMsg
						})
						reject(res)
					}
				}
			})

		})
	})
}
/**
 * 小程序手机号快捷登录
 * @param code 快捷登录获得的code
 * @example
 * //示例
 * <button open-type="getPhoneNumber" \@getphonenumber="phoneLogin">手机快捷登录</button>
 *
 * phoneLogin(e){
 * 	if(e.code){
 * 		mpPhoneLogin(e.code).then(r=>{
 * 			//做登录成功的逻辑
 *  	})
 * 	}
 * }
 *
 */
export function mpPhoneLogin(code, uri = 'client/mp_phone_login') {
	return new Promise((resolve, reject) => {
		formPost(uri, {
			code: code
		}, '登录中,请稍后').then(r => {
			//登录成功
			let user = r.user
			user.isNew=r.isNew
			//存储数据
			token(user.token)
			Uk(r.uk)
			Un(user.userType + user.username)
			userInfo(user)
			resolve(user)
		}).catch(e => {
			uni.showToast({
				icon: 'fail',
				title: e.message
			})
			reject(e)
		})
	})

}
/**
 * 发送手机登录验证码，5分钟有效
 * @param {String} phone
 */
export function sendPhoneCode(phone){
	//sendPhoneCode
	let t=Date.now()
	return formPost('client/sendPhoneCode',{
		phone:encrypt(phone,t+''),
		t:t
	},"验证码发送中")
}
/**
 * 手机验证码登录
 */
export function phoneCodeLogin(phone,code){
	return new Promise((reslove, reject) => {
		formPost('client/phoneCodeLogin', {
			phone:phone,
			code: code
		}, '登录中,请稍后').then(r => {
			//登录成功
			let user = r.user
			user.isNew=r.isNew
			//存储数据
			token(user.token)
			Uk(r.uk)
			Un(user.userType + user.username)
			userInfo(user)
			reslove(user)
		}).catch(e => {
			uni.showToast({
				icon: 'error',
				title: e.message
			})
			reject(e)
		})
	})
}

/**
 * 用户退出，并重启到指定页面
 * @param to
 */
export const logout = (to = loginPage) => {
	userInfo(null)
	token(null)
	Uk(null)
	Un(null)
	if (to) {
		// uni.redirectTo({
		// 	url: to,
		// })
		uni.reLaunch({
			url:to
		})
	}
}

/**
 * 缓存本地配置文件
 * @param key
 * @return {(function(*): (*|undefined))|*}
 */
function createConfig(key) {
	return function config(data) {
		if (arguments.length == 0) {
			return uni.getStorageSync(key)
		} else {
			if (data == null) {
				uni.removeStorageSync(key)
			} else {
				uni.setStorageSync(key, data)
			}
		}
	}
}
const sysConfig = createConfig("sys_config")
const userInfo = createConfig("userInfo")

const Uk = createConfig('uk')
const Un = createConfig('un')
const token = createConfig('token')
/**
 * 用户登录时调用存储信息加密
 *
 * @param {String} username 用户名
 * @param {String} password 密码
 * @param {String} appSign 项目签名
 */
function setLoginNum(username, password, appSign) {
	//let t = Date.now()
	// let key = config.value['PlatformConfig.SystemName'] + t
	uni.setStorageSync('uk', md5(username + "$" + password) + appSign)
	uni.setStorageSync('un', 't' + username)
}
/**
 * Base64URL编码

 * @param {Object} input
 */
function base64Encode(input) {
	const _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
	let output = "";
	let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
	let i = 0;

	while (i < input.length) {
		chr1 = input[i++];
		chr2 = input[i++];
		chr3 = input[i++];

		enc1 = chr1 >> 2;
		enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
		enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
		enc4 = chr3 & 63;

		if (isNaN(chr2)) {
			enc3 = enc4 = 64;
		} else if (isNaN(chr3)) {
			enc4 = 64;
		}

		output =
			output +
			_keyStr.charAt(enc1) +
			_keyStr.charAt(enc2) +
			_keyStr.charAt(enc3) +
			_keyStr.charAt(enc4);
	}
	return output;
};

function leftPad(s, char, len) {
	return new Array(len - s.length + 1).join(char) + s
}

function sign(v) {
	return base64Encode(ConvertHex.toBytes(md5(v)))
}
/**
 * 生成页面登录token

 * @param {Object} value
 * @param {Object} salt
 * @param {Object} expire
 */
function genToken(value, salt, expire) {
	let time = parseInt(Date.now() / 1000) + expire;
	let t = leftPad(time.toString(36), '0', 7);
	let v = value + time + salt;
	return t + sign(v) + base64Encode(ConvertUtf8.toBytes(value));
}

function tryToken() {
	let un = uni.getStorageSync('un')
	let uk = uni.getStorageSync('uk')
	if (un && uk) {
		let tk = genToken(un, uk, 1800);
		uni.setStorageSync('token', tk)
		return tk;
	}
	return null
}
export const getToken = () => {
	let token = uni.getStorageSync("token")
	if (token) {
		let t = parseInt(token.substr(0, 7), 36)
		let n = Math.floor(Date.now() / 1000)
		if (n > t - 300) {
			let ntk = tryToken()
			if (ntk) {
				token = ntk
			}
		}
		return token
	} else {
		let ntk = tryToken()
		if (ntk) {
			return ntk
		}
	}
}
// 请求拦截器拦截请求是调用，传入header
function setRequestHeader(header = {}) {
	let token = uni.getStorageSync("token")
	if (token) {
		let t = parseInt(token.substr(0, 7), 36)
		let n = Math.floor(Date.now() / 1000)
		if (n > t - 300) {
			let ntk = tryToken()
			if (ntk) {
				token = ntk
			}
		}
		header.token = token;
		return token
	} else {
		let ntk = tryToken()
		if (ntk) {
			header.token = ntk;
			return ntk
		}
	}
}
